package com.dd.keel.core.beans;

import java.util.Properties;
import java.io.File;









import java.lang.management.ManagementFactory;

import com.dd.keel.core.beans.factory.KeelBeanException;
import com.dd.keel.core.beans.factory.KeelBeanFactory;
import com.dd.keel.core.common.ini.IniReader;
import com.dd.keel.core.common.shutdown.ShutdownClient;
import com.dd.keel.core.common.shutdown.ShutdownServer;
import com.dd.keel.core.common.shutdown.Shutdownable;
import com.dd.keel.core.common.utils.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Bean Server
 * <p>Responsibility :
 * <p>1, Initialize all beans 
 * <p>2, Startup bean's run context if necessary
 * <p>3, Shutdown all beans with destory their run context
 * <p>rt.dat format : shutdown_port
 * @author Kevin.XU
 *
 */
public class BeanServer implements Shutdownable{
	
	final static private Logger LOGGER = LoggerFactory.getLogger(BeanServer.class);
	
	private ShutdownServer shutdownServer = null;
	private ShutdownClient shutdownClient = null;
	private int shutdown_port = 0;
	private String beansLocations = "classpath:/keel-beans/*-beans.xml,classpath*:META-INF/spring/*-beans.xml";
	private String runtime_config_file = FileUtil.retrieveTempFilepath("rt.dat");
	private String singleton_file = FileUtil.retrieveTempFilepath("singleton.dat");
	String pid_file = FileUtil.retrieveTempFilepath("mypid");
	private ApplicationSingleton applicationSingleton = null;
	
	public static void main(String[] args)
	{
		BeanServer beanServer = new BeanServer();
		beanServer.entrance(new String[]{"startup"});
	}
	
	public void entrance(String[] args)
	{
		if(args.length==1)
		{
			if(args[0].equalsIgnoreCase("startup"))
			{
				LOGGER.info("Begin to startup BeanServer ...");
				applicationSingleton = new ApplicationSingleton(singleton_file);
				if(applicationSingleton.acquire())
				{
					try{
						//write pid
						String jvmName = ManagementFactory.getRuntimeMXBean().getName();
						String pid = jvmName.split("@")[0];
						FileUtil.writeTextToFile(pid, pid_file, "UTF-8");
						readConfig(true);
						startup();
					}catch(Exception ex){
						LOGGER.error(ex.getMessage(), ex);
					}
				}
				else
				{
					System.out.println("The program is running, can't be startup twice!");
				}
			}
			else if(args[0].equalsIgnoreCase("shutdown"))
			{
				LOGGER.info("Begin to shutdown BeanServer ...");
				try {
					readConfig(false);
					shutdownFromClient();
				} catch (Exception ex) {
					LOGGER.error(ex.getMessage(), ex);
				}
			}
			else
			{
				StringBuffer sb = new StringBuffer();
				sb.append("Wrong parameter!").append('\n');
				sb.append("Accepted parameter : ").append('\n');
				sb.append("[startup]  : Startup Server").append('\n');
				sb.append("[shutdown] : Shutdown Server").append('\n');
				System.out.println(sb.toString());
			}
		}
	}
	
	private void deleteRuntimeDataFile()
	{
		File runtimeDataFile = new File(runtime_config_file);
		if(runtimeDataFile.exists())
		{
			runtimeDataFile.delete();
		}
	}
	
	private void getShutdownPort(boolean whenStartup)
	{
		if(whenStartup)
		{
			shutdown_port = NetUtil.randomTCPPort();
			LOGGER.info("shutdown port is {}", shutdown_port );
			FileUtil.writeTextToFile(shutdown_port+"", runtime_config_file, "UTF-8");
		}
		else
		{
			String str_shutdown_port = FileUtil.readTextFromFile(runtime_config_file, "UTF-8");
			if(str_shutdown_port!=null)
			{
				str_shutdown_port = str_shutdown_port.trim();
				if(!str_shutdown_port.equals(""))
				{
					shutdown_port = Integer.parseInt(str_shutdown_port);
				}
			}
		}
	}
	
	private boolean readConfigFrom_server_ini(boolean whenStartup) throws Exception
	{
		LOGGER.info("try read {}", "server.ini" );
		String server_config_file = FileUtil.retrieveConfigFilepath("server.ini");
		File server_file = new File(server_config_file);
		IniReader iniReader = null;
		try{
			if(server_file.exists())
			{
				iniReader = new IniReader(server_file);
			}
			else
			{
				iniReader = new IniReader("server.ini",this.getClass());
			}
		}catch(Exception ex){
		}
		
		if(iniReader==null)
		{
			LOGGER.error( "Not found server.ini!" );
			return false;
		}
		getShutdownPort(whenStartup);		
		if(!whenStartup) return true;
		Properties services_props = iniReader.getSectionProps("services");
		if(services_props!=null && !services_props.isEmpty() && services_props.containsKey("beans.locations"))
		{
			beansLocations = services_props.getProperty("beans.locations");
		}
		return true;
	}
	
	private void readConfig(boolean whenStartup) throws Exception
	{
		if(!readConfigFrom_server_ini(whenStartup))
		{
			LOGGER.error("Read {} failed", "server.ini" );
		}
		else
		{
			LOGGER.info("Have read {}", "server.ini" );
		}
	}
	
	public void startup() throws Exception
	{
		if(shutdown_port > 0) {
			shutdownServer = new ShutdownServer(this.getClass().getSimpleName(),this,shutdown_port);
			shutdownServer.start();
			KeelBeanFactory.init(beansLocations);
		} else {
			System.out.println("Shutdown port Not Set, Please fill it in server.ini!");
			System.out.println("System exit!");
			System.exit(1);
		}
	}
	
	public void shutdown()
	{
		try {
			KeelBeanFactory.destroy();
		} catch (KeelBeanException ex) {
			LOGGER.error(ex.getMessage(), ex);
		}
		applicationSingleton.dequire();
		deleteRuntimeDataFile();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {}
		LOGGER.info("Shutdown!");
		System.exit(0);
	}
	
	public void shutdownFromClient()
	{
		shutdownClient = new ShutdownClient(shutdown_port);
		shutdownClient.shutdown();
	}
	
}
